#ifndef NEURE_H
#define NEURE_H
#include <QByteArray>
#include <QString>
#include <QTimer>
#include <QElapsedTimer>
#include <QtserialPort/QserialPort>

#define		FRAME_HEAD					( 0xF0 )
#define		FRAME_END					( 0xF7 )
#define     FRAME_SRV_IDX				( 2 )
#define     FRAME_CHECK_START_IDX       ( 1 )
#define     EXP_SRV						( 0x63 )
#define     EXP_SUB_SRV                 ( 0x10 )
#define		NEURE_ASSIGN_TIME_MS		( 1000 )

#define     SET_RGB_CMD_ID              ( 0x09 )
#define     STOP_CMD_ID					( 0x0C )
#define     FORWARD_CMD_ID              ( 0x0D )
#define     RIGHT_TURN_CMD_ID           ( 0x0F )
#define     LEFT_TURN_CMD_ID            ( 0x10 )
#define     BACKWARD_CMD_ID             ( 0x0E )
#define     MOTOR_CTRL_CMD_ID           ( 0x11 )
#define     CALIBRATION_CMD_ID          ( 0x6F )
#define     REPORT_CMD_ID               ( 0x7F )

#define     RGB_REPORT_SENSOR_ID        ( 0x01 )

class neure : public QObject
{
	Q_OBJECT

public:
	neure(QSerialPort *);
	~neure();
	
	// System
	void assignDevId(void);
	void getFirmware(void);
	void send(QByteArray);
	
	// Car controll
	void forward(quint8);
	void backward(quint8);
	void motorControl(qint16, qint16);
	void stop();
	void leftTurn();
	void rightTurn();

	// Color
	void calibration(void);
	void getRgb(void);
	void getColor(void);
	void getEnv(void);
	void getGray(void);
	void getVisibleReflect(void);
	void getIrReflect(void);
	void getObstacle(void);

	void setR(void);
	void setG(void);
	void setB(void);

	// Polling
	void pollingRgb(bool);      // None
	void pollingRgb(void);		// Changed
	void pollingRgb(quint32);	// Period

	void pollingColor(bool);    // None
	void pollingColor(void);	// Changed
	void pollingColor(quint32);	// Period

	void pollingEnv(bool);      // None
	void pollingEnv(void);      // Changed
	void pollingEnv(quint32);	// Period

	void pollingGray(bool);      // None
	void pollingGray(void);      // Changed
	void pollingGray(quint32);	 // Period

	void pollingVisibleReflect(bool);             // None
	void pollingVisibleReflect(void);             // Changed
	void pollingVisibleReflect(quint32);	      // Period

	void pollingIrReflect(bool);				// None
	void pollingIrReflect(void);				// Changed
	void pollingIrReflect(quint32);				// Period

	void pollingObstacle(bool);				   // None
	void pollingObstacle(void);				   // Changed
	void pollingObstacle(quint32);			   // Period

	void pollingDcCurrent(bool);			   // None
	void pollingDcCurrent(void);		       // Changed
	void pollingDcCurrent(quint32);			   // Period

private:
	quint8 calcCheckSum(QByteArray);
	bool checkSum(QByteArray);
	quint16 readBigShort(QByteArray);
	QByteArray build_long(quint32);

signals:
	void logInfo(QString);
	void devOnlineUpdate(bool, quint8);
	void firmwareUpdate(QString);
	void rgbUpdate(quint16, quint16, quint16);
	void colorUpdate(quint16, quint16, quint16, QString);
	void envUpdate(quint8);
	void grayUpdate(quint8);
	void visibleReflectUpdate(quint8);
	void irReflectUpdate(quint8);
	void obstacleUpdate(quint8);
	void dcCurrentUpdate(quint16, quint16);

private slots:
	void recvData(void);
	void proFrame(QByteArray);
	void proAssignDevId(QByteArray);
	void proGetFirmware(QByteArray);
	void proGetRgb(QByteArray);
	void proGetColor(QByteArray);
	void proGetEnv(QByteArray);
	void proGetGray(QByteArray);
	void proGetVisibleReflect(QByteArray);
	void proGetIrReflect(QByteArray);
	void proGetObstacle(QByteArray);
	void proGetDcCurrent(QByteArray);

private:
	enum
	{
		DEV_ID = 0x10,
		FIRMWARE = 0x12,
	};

	typedef enum
	{
		WHITE = 0,
		PINK = 1,
		RED = 2,
		ORANGE = 3,
		YELLOW = 4,
		GREEN = 5,
		CYAN = 6,
		BLUE = 7,
		PURPLE = 8,
		BLACK = 9,
		GOLD = 10,
		NO_COLOR = 0xFF,
	} color_id_e;

	typedef enum
	{
		GET_RGB = 1,
		GET_COLOR = 2,
		GET_ENV = 3,
		GET_GRAY = 4,
		GET_VISIBLE_REFLECT = 5,
		GET_IR_REFLECT = 6,
		IF_IN_GRAY_RANGE = 7,
		IF_OBSTACLE = 8,
		DC_CURRENT = 0x0A,
	} get_cmd_id_e;

	typedef enum
	{
		RGB_SENSOR_ID = 1,
		COLOR_SENSOR_ID = 2,
	    ENV_SENSOR_ID = 3,
		GRAY_SENSOR_ID = 4,
		VISIBLE_REFLECT_SENSOR_ID = 5,
		IR_REFLECT_SENSOR_ID = 6,
		OBSTACLE_SENSOR_ID = 8,
		DC_CURRENT_SAMPLE_SENSOR_ID = 0x0A,
	} reported_sensor_id_e;

	typedef enum
	{
		REPORT_NONE = 0,
		REPORT_CHG = 1,
		REPORT_PRD = 2,
	} reported_mode_e;

	bool m_r, m_g, m_b;
	QSerialPort *m_ser;
	bool m_header;
	QByteArray m_frame;
	int m_online_cnt;
	bool m_dev_online;
	quint8 m_dev_id;

	// Geting & setting
	void sendGetCmd(get_cmd_id_e);

	void setRGB(bool r, bool g, bool b);

	// Polling
	void polling(reported_sensor_id_e, reported_mode_e, quint32);

	// Statistics
	QElapsedTimer m_elapsedTimer;
	int m_start_tick, m_end_tick;
};

#endif // NEURE_H